package ufrgs.ia.tetralath.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import ufrgs.ia.tetralath.Tetralath;
import ufrgs.ia.tetralath.Tetralath.BOARD_STATE;
import ufrgs.ia.tetralath.Tetralath.PLAYER;
import ufrgs.ia.tetralath.brain.Minimax;
import ufrgs.ia.tetralath.models.GameMomentum;
import ufrgs.ia.tetralath.models.GamePiece;

public class MainWindow extends JPanel {

	/**
	 * This is the serialVersonUID automatically generated by eclipse i have no
	 * idea what the heck is it for
	 */
	private static final long serialVersionUID = 1872629073560702019L;
	private final String playerIndicator = "Turno do: ";

	private Dimension informationLayoutDimention;
	private Dimension gameLayoutDimention;

	// game information components
	private JLabel currentlyPlaying;
	private JLabel jlabelMinimaxHeigh;
	private JButton jbuttonChangeHeigh; 
	
	private JTextField textFieldCurrentMinimaxHeight;
	private JButton startPlaying;
	

	// here is where all the layouts filled with gamepieces will be put
	private JPanel gameLayout;
	
	
	private BOARD_STATE state = BOARD_STATE.NONE;
	
	/** listener that will be hearing clicks in the game cells */
	private GameActionListener gamePieceActionListener;
	private SettingsActionListener settingsActionListener;

	/** just a set of possible opennings */
	private boolean haveStrategy;
	private List<Point> openningList = Arrays.asList(new Point(3, 4), new Point(5, 4), new Point(6, 8), new Point(4, 6), new Point(6, 4), new Point(3, 5));
	
	private Minimax minimax = new Minimax();
	
	public MainWindow() {
		super(new BorderLayout());

		// preferred size of windows
		Dimension windowSize = new Dimension(750, 600);

		informationLayoutDimention = new Dimension(750, 100);
		gameLayoutDimention = new Dimension(750, 500);

		setSize(windowSize);
		setPreferredSize(windowSize);

		add(gamePane(), BorderLayout.CENTER);
	}

	/**
	 * Creates the game pane and its content
	 * @return the new created pane
	 */
	private JPanel gamePane() {

		JPanel gamePane = new JPanel();
		gamePane.setBackground(Color.black);
		gamePane.setLayout(new BoxLayout(gamePane, BoxLayout.Y_AXIS));

		gamePieceActionListener = new GameActionListener();
		settingsActionListener = new SettingsActionListener();
		
		gamePane.add(informationLayout());
		gamePane.add(boardLayout());

		return gamePane;
	}

	private JPanel informationLayout() {
		JPanel informationLayout = new JPanel();
		informationLayout.setBorder(BorderFactory.createTitledBorder("Informações"));
		informationLayout.setPreferredSize(informationLayoutDimention);
		informationLayout.setSize(informationLayoutDimention);

		JPanel contentLayout = new JPanel();
		contentLayout.setLayout(new BoxLayout(contentLayout, BoxLayout.Y_AXIS));

		JPanel infoLayout = new JPanel();
		infoLayout.setLayout(new BoxLayout(infoLayout, BoxLayout.X_AXIS));
		currentlyPlaying = new JLabel(playerIndicator + Tetralath.currentPlayer.getName());
		
		startPlaying = new JButton("Começar");
		startPlaying.addActionListener(settingsActionListener);
		
		infoLayout.add(currentlyPlaying);
		infoLayout.add(startPlaying);
		
		contentLayout.add(infoLayout);
		
		
		JPanel heighSettingsLayout = new JPanel();
		heighSettingsLayout.setLayout(new BoxLayout(heighSettingsLayout, BoxLayout.X_AXIS));
		
		jbuttonChangeHeigh = new JButton("Mudar altura");
		jbuttonChangeHeigh.addActionListener(settingsActionListener);
		
		jlabelMinimaxHeigh = new JLabel("Altura do minimax");
		textFieldCurrentMinimaxHeight = new JTextField("3");
		
		heighSettingsLayout.add(jlabelMinimaxHeigh);
		heighSettingsLayout.add(textFieldCurrentMinimaxHeight);
		heighSettingsLayout.add(jbuttonChangeHeigh);
		contentLayout.add(heighSettingsLayout);
		
		
		
		

		informationLayout.add(contentLayout);
		return informationLayout;
	}

	/**
	 * This is the panel where the game cells are going to be displayed every
	 * row of the game cell will be a panel
	 * 
	 * @return mounted game layout
	 */
	private JPanel boardLayout() {
		gameLayout = new JPanel();
		gameLayout.setBorder(BorderFactory.createTitledBorder("Tabuleiro"));
		gameLayout.setLayout(new BoxLayout(gameLayout, BoxLayout.Y_AXIS));
		gameLayout.setPreferredSize(gameLayoutDimention);
		gameLayout.setSize(gameLayoutDimention);

		List<Integer> cellsPerRow = Arrays.asList(5, 6, 7, 8, 9, 8, 7, 6, 5);

		JPanel boardRow;
		GamePiece gamePiece;

		for (int rowIndex = 0; rowIndex < Tetralath.BOARD_DIMENSION; rowIndex++) {

			boardRow = new JPanel();

			for (int columnIndex = 0; columnIndex < cellsPerRow.get(rowIndex); columnIndex++) {
				if (rowIndex > 4) {
					gamePiece = new GamePiece(gamePieceActionListener, rowIndex, columnIndex + (rowIndex - 4));
					gamePiece.setToolTipText("Owner: NONE - Position: " + "(" + rowIndex + ", " + (columnIndex + (rowIndex - 4)) + ")");
				} else {
					gamePiece = new GamePiece(gamePieceActionListener, rowIndex, columnIndex);
					gamePiece.setToolTipText("Owner: NONE - Position: " + "(" + rowIndex + ", " + columnIndex + ")");
				}

				boardRow.add(gamePiece);
			}

			gameLayout.add(boardRow);

		}
		return gameLayout;
	}
	
	private class SettingsActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent event) {
			
			if(event.getSource() == jbuttonChangeHeigh) {
				
				try {
					int typedValue = Integer.valueOf(textFieldCurrentMinimaxHeight.getText());
					Minimax.MAX_MINIMAX_DEPTH = typedValue;
				} catch (NumberFormatException e) {
					textFieldCurrentMinimaxHeight.setText(String.valueOf(Minimax.MAX_MINIMAX_DEPTH));
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		
				
			} else {
			
				Tetralath.currentPlayer = PLAYER.MINIMAX;
				
				if(state == BOARD_STATE.NONE || state == BOARD_STATE.MINIMAX_MOVE_BLOCK || state == BOARD_STATE.HUMAN_MOVE_BLOCK) {
					
					new Thread(new Runnable() {
	
						@Override
						public void run() {
							makeMinimaxMove();	
						}
					}).start();
				}
				
				System.gc();
			}
			
		}
		
	}

	private class GameActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent actionEvent) {

			GamePiece clickedCellPiece = (GamePiece) actionEvent.getSource();
			
			if(state == BOARD_STATE.NONE || state == BOARD_STATE.MINIMAX_MOVE_BLOCK || state == BOARD_STATE.HUMAN_MOVE_BLOCK) {
					
				clickedCellPiece.setClicked(Tetralath.currentPlayer, Tetralath.gameBoard);
				clickedCellPiece.removeActionListener(gamePieceActionListener);
				
				
				Tetralath.currentGameMomentum.setNewMove(clickedCellPiece.getPiecePosition(), Tetralath.currentPlayer);
				makeMove();
			}
			
			if(state == BOARD_STATE.NONE || state == BOARD_STATE.MINIMAX_MOVE_BLOCK || state == BOARD_STATE.HUMAN_MOVE_BLOCK) {
				
				new Thread(new Runnable() {

					@Override
					public void run() {
						makeMinimaxMove();	
					}
				}).start();
			}
			
			System.gc();
			
		}
		
	}
	
	private void makeMinimaxMove() {
		GamePiece aux;
		GameMomentum currentMomentum;
		GameMomentum newMomentum;
		
		newMomentum = minimax.getBestMove(Tetralath.currentGameMomentum);
		
		haveStrategy = false;
		
		if(newMomentum.getBoardState(Tetralath.PLAYER.MINIMAX) == Tetralath.BOARD_STATE.NONE) {
			for(Point currentPoint : openningList) {
				if(Tetralath.positionHaveNoOwner(currentPoint.x, currentPoint.y)) {
					aux = findGamePieceByCoordenates(currentPoint);
					aux.setClicked(Tetralath.currentPlayer, Tetralath.gameBoard);
					Tetralath.currentGameMomentum.setNewMove(currentPoint, Tetralath.currentPlayer);
					aux.removeActionListener(gamePieceActionListener);
					openningList.remove(aux);
					haveStrategy = true;
					break;
				}
			}
		} 
		
		if(!haveStrategy) {
			Tetralath.currentGameMomentum.setNewMove(newMomentum.getNewMove(), Tetralath.currentPlayer);
			aux = findGamePieceByCoordenates(newMomentum.getNewMove());
			aux.setClicked(Tetralath.currentPlayer, Tetralath.gameBoard);
			aux.removeActionListener(gamePieceActionListener);
		}
		
		makeMove();
	}
	
	
	
	private GamePiece findGamePieceByCoordenates(Point position) {
		GamePiece gamePiece;
		int x = position.x;
		int y = position.y;
		
		
		JPanel row = (JPanel)gameLayout.getComponent(x);
		
		if(x < 5) {
			gamePiece = (GamePiece)row.getComponent(y);
		}
		else {
			gamePiece = (GamePiece)row.getComponent(y + (4 - x));
		}
		
		return gamePiece;
	}
	
	private void makeMove() {
		
		state = Tetralath.currentGameMomentum.getBoardState(Tetralath.currentPlayer);
		
		switch(state) {
			case DRAW:
				JOptionPane.showInputDialog(this, "O jogo empatou");
			break;
			case HUMAN_MOVE_LOSS:
				JOptionPane.showInputDialog(this, "O oponente ganhou");
				break;
			case HUMAN_MOVE_WIN:
				JOptionPane.showInputDialog(this, "O oponente se matou");
				break;
			case MINIMAX_MOVE_LOSS:
				JOptionPane.showInputDialog(this, "Eu me matei");
				break;
			case MINIMAX_MOVE_WIN:
				JOptionPane.showInputDialog(this, "Eu ganhei");
				break;
			case NONE:
				break;
		}

		// change the player
		if (Tetralath.currentPlayer == PLAYER.HUMAN)
			Tetralath.currentPlayer = PLAYER.MINIMAX;
		else
			Tetralath.currentPlayer = PLAYER.HUMAN;

		currentlyPlaying.setText(playerIndicator + Tetralath.currentPlayer.getName());
		Tetralath.currentRoundNumber++;
	}
}
